package com.example.podcaster.services;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Locale;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xml.sax.SAXException;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import com.example.podcaster.database.DBApplication;
import com.example.podcaster.rss.RSSChannel;
import com.example.podcaster.rss.RSSChannelHandler;
import com.example.podcaster.services.UpdateService.UpdateState;

public class UpdateService extends Service
{
    public enum UpdateState
    {
        SUCESSFULLY, FAILED, UNCOMPLETED
    }

    public class UpdateServiceBinder extends Binder
    {
        public UpdateService getService()
        {
            return UpdateService.this;
        }
    }

    @SuppressLint("UseSparseArrays")
	private HashMap<Integer, UpdateThread> updateThreads = new HashMap<Integer, UpdateThread>();

    private final UpdateServiceBinder localBinder = new UpdateServiceBinder();

    private IUpdateListener updateListener;

    public void onCreate()
    {
        super.onCreate();
    }

    public synchronized boolean updatePodcast(int id)
    {
        if (updateThreads.containsKey(id))
        {
            return false;
        }

        updateThreads.put(id, new UpdateThread(this, id));
        return true;
    }

    public synchronized UpdateState getUpdateState(int id)
    {
        if (updateThreads.containsKey(id))
        {
            return updateThreads.get(id).getUpdateState();
        }
        else
        {
            return null;
        }
    }

    public synchronized boolean removeUpdate(int id)
    {
        if (updateThreads.containsKey(id))
        {
            updateThreads.remove(id);
            return true;
        }
        else
        {
            return false;
        }
    }

    @Override
    public IBinder onBind(Intent arg0)
    {
        return localBinder;
    }

    public void setUpdateListener(IUpdateListener updateListener)
    {
        this.updateListener = updateListener;
    }

    public void removeUpdateListener()
    {
        this.updateListener = null;
    }

    public void updateTerminated(int id)
    {
        if (null != updateListener)
        {
            updateListener.updateTerminated(id);
        }
    }
}

class UpdateThread extends Thread
{
    private UpdateState updateState = UpdateState.UNCOMPLETED;

    SQLiteDatabase sqLiteDatabase = DBApplication.getSqliteDatabase();

    private final UpdateService updateService;

    private final int id;

    private final SimpleDateFormat dateformat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
    
    public UpdateThread(UpdateService updateService, int id)
    {
        this.updateService = updateService;
        this.id = id;

        // sdf.setTimeZone(TimeZone.getTimeZone("GTM"));
        this.start();
    }

    @Override
    public void run()
    {
        Cursor cursor_url = sqLiteDatabase.rawQuery("SELECT `url` FROM `podcast` WHERE `_id` = ?;", new String[]
        { String.valueOf(id) });

        if (!cursor_url.moveToFirst())
        {
            this.setUpdateState(UpdateState.FAILED);
            this.updateService.updateTerminated(id);
            return;
        }

        String url = cursor_url.getString(0);
        cursor_url.close();

        RSSChannelHandler rssChannelHandler = new RSSChannelHandler();

        HttpClient client = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = null;

        try
        {
            response = client.execute(httpGet);
        }
        catch (ClientProtocolException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (null != response)
        {
            if (response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();

                try
                {
                    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
                    SAXParser saxParser = saxParserFactory.newSAXParser();

                    saxParser.parse(entity.getContent(), rssChannelHandler);
                }
                catch (ParserConfigurationException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                catch (SAXException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                catch (IllegalStateException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        if (null != rssChannelHandler.getRssChannel())
        {
            try
            {
                sqLiteDatabase.beginTransaction();
                this.updatePodcast(rssChannelHandler.getRssChannel());
                sqLiteDatabase.setTransactionSuccessful();
                sqLiteDatabase.endTransaction();
                this.setUpdateState(UpdateState.SUCESSFULLY);
            }
            catch (SQLiteException e)
            {
                this.setUpdateState(UpdateState.FAILED);
            }
        }
        else
        {
            this.setUpdateState(UpdateState.FAILED);
        }
        this.updateService.updateTerminated(id);
    }

    private synchronized void setUpdateState(UpdateState updateState)
    {
        this.updateState = updateState;
    }

    public synchronized UpdateState getUpdateState()
    {
        return this.updateState;
    }

    private void updatePodcast(RSSChannel rssChannel)
    {

        ContentValues contentValues = new ContentValues();
        contentValues.put("title", rssChannel.getChannelTitle());
        contentValues.put("author", rssChannel.getChannelAuthor());
        contentValues.put("image_url", rssChannel.getChannelImageURL());
        contentValues.put("description", rssChannel.getChannelDescription());
        contentValues.put("last_updated", (int) (System.currentTimeMillis() / 1000));
        sqLiteDatabase.update("podcast", contentValues, "_id = ?", new String[]
        { String.valueOf(id) });

        for (int i = 0; i < rssChannel.getEpisodeTitle().length; ++i)
        {
            if (rssChannel.getEpisodeGuid()[i] != null)
            {
                this.updateEpisodeWithGuid(rssChannel, i, rssChannel.getEpisodeGuid()[i]);
            }
            else
            {
                this.updateEpisodeWithGuid(rssChannel, i, rssChannel.getEpisodeTitle()[i] + rssChannel.getEpisodePubDate()[i]);
            }
        }

        Cursor image_url = DBApplication.getSqliteDatabase().rawQuery("SELECT `image_url` FROM `image` WHERE `image_url` = ?;", new String[]
        { rssChannel.getChannelImageURL() });
        if (!image_url.moveToFirst())
        {
            this.loadImage(rssChannel.getChannelImageURL());
        }
        image_url.close();
    }

    private void loadImage(String url)
    {
        InputStream is = null;
        ByteArrayOutputStream bout = null;
        try
        {
            is = (InputStream) new URL(url).getContent();
            bout = new ByteArrayOutputStream();

            int l = -1;
            byte[] b = new byte[512];
            while ((l = is.read(b)) != -1)
            {
                bout.write(b, 0, l);
            }

            ContentValues contentValues = new ContentValues();

            contentValues.put("image_url", url);
            contentValues.put("file", bout.toByteArray());

            Log.d(this.getClass().getName(), String.valueOf(sqLiteDatabase.insert("image", null, contentValues)));

        }
        catch (MalformedURLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally
        {
            if (null != is)
            {
                try
                {
                    is.close();
                }
                catch (IOException e)
                {
                }
            }
            if (null != bout)
            {
                try
                {
                    bout.close();
                }
                catch (IOException e)
                {
                }
            }
        }
    }

    private void updateEpisodeWithGuid(RSSChannel rssChannel, int index, String guid)
    {
        Cursor cursor_id = sqLiteDatabase.rawQuery("SELECT `_id` FROM `episode` WHERE `guid` = ?;", new String[]
        { guid });

        if (cursor_id.moveToFirst())
        {
            cursor_id.close();
            this.updateEpisode(rssChannel, index, guid);
        }
        else
        {
            cursor_id.close();
            this.insertEpisode(rssChannel, index, guid);
        }
    }

    private void insertEpisode(RSSChannel rssChannel, int index, String guid)
    {
        ContentValues contentValues = new ContentValues();

        contentValues.put("podcast_id", id);
        contentValues.put("guid", guid);
        contentValues.put("url", rssChannel.getChannelLink());
        contentValues.put("media_url", rssChannel.getEpisodeMediaURL()[index]);
        contentValues.put("title", rssChannel.getEpisodeTitle()[index]);
        if (null != rssChannel.getEpisodePubDate()[index])
        {
            try
            {
                // @SuppressWarnings("deprecation")
                // Date d = new Date(rssChannel.getEpisodePubDate()[index]);
                int datetime = (int) (dateformat.parse(rssChannel.getEpisodePubDate()[index]).getTime() / 1000);
                contentValues.put("pubdate", datetime);
            }
            catch (Exception e)
            {
                contentValues.putNull("pubdate");
            }
        }
        else
        {
            contentValues.putNull("pubdate");
        }
        if (null != rssChannel.getEpisodePubDate()[index])
        {
            contentValues.put("author", rssChannel.getEpisodeAuthor()[index]);
        }
        else
        {
            contentValues.putNull("author");
        }
        if (null != rssChannel.getEpisodeDescription()[index])
        {
            contentValues.put("description", rssChannel.getEpisodeDescription()[index]);
        }
        else
        {
            contentValues.putNull("description");
        }
        contentValues.putNull("file_path");
        contentValues.put("is_favourite", 0);

        sqLiteDatabase.insert("episode", null, contentValues);
    }

    private void updateEpisode(RSSChannel rssChannel, int index, String guid)
    {
        ContentValues contentValues = new ContentValues();

        contentValues.put("media_url", rssChannel.getEpisodeMediaURL()[index]);
        contentValues.put("title", rssChannel.getEpisodeTitle()[index]);
        if (null != rssChannel.getEpisodePubDate()[index])
        {
            try
            {
                // @SuppressWarnings("deprecation")
                // Date d = new Date(rssChannel.getEpisodePubDate()[index]);
                int datetime = (int) (dateformat.parse(rssChannel.getEpisodePubDate()[index]).getTime() / 1000);
                contentValues.put("pubdate", datetime);
            }
            catch (Exception e)
            {
                contentValues.putNull("pubdate");
            }
        }
        else
        {
            contentValues.putNull("pubdate");
        }
        if (null != rssChannel.getEpisodeAuthor()[index])
        {
            contentValues.put("author", rssChannel.getEpisodeAuthor()[index]);
        }
        else
        {
            contentValues.putNull("author");
        }
        if (null != rssChannel.getEpisodeDescription()[index])
        {
            contentValues.put("description", rssChannel.getEpisodeDescription()[index]);
        }
        else
        {
            contentValues.putNull("description");
        }

        sqLiteDatabase.update("episode", contentValues, "guid = ?", new String[]
        { guid });
    }
}